home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Nebula 2
/
Nebula Two.iso
/
SourceCode
/
MiniExamples
/
AppKit
/
TextORama
/
TurboTFCell.m
< prev
Wrap
Text File
|
1995-06-12
|
7KB
|
253 lines
/* TurboTFCell.m
*
* TurboTFCell is a subclass of TextFieldCell which supports
* a) length-watching on a string -- maxLength [length of 0
* indicates that length-watching is not active]
* b) auto-jumping to nextText if the maximum is reached
* c) acceptsReturn will cause the Return character to be
* interpreted literally rather than as a signal to end editing
*
*
* You may freely copy, distribute, and reuse the code in this example.
* NeXT disclaims any warranty of any kind, expressed or implied, as to its
* fitness for any particular use.
*
* Written by: Sharon Zakhour
* Created: Oct/91
*/
#import "TurboTFCell.h"
@implementation TurboTFCell
/* In order for the length watching (and auto-jumping since that is
* determined by length) to work properly, the character and text
* filters need to know the identity of the cell they are working with.
*/
static id theCell = NULL;
- init
{
return [self initTextCell:""];
}
- initTextCell: (const char*) aString
{
[super initTextCell:aString];
// Initialize these to the default TextField behavior
originalText = NULL;
customTextFilter = (NXTextFilterFunc)lengthFilter;
[self setAutoJump: NO forLength: 0];
[self setAcceptsReturn: NO];
return self;
}
- free
{
if (originalText)
free(originalText);
originalText = NULL;
return[super free];
}
/* The primary reason I've overridden select: and edit: (below) is to set
* the local static variable "theCell" to self. The filter functions must know
* about the current cell in order to query it for information on length,
* autojumping, etc. The only way that a cell becomes active are
* through one of these methods.
*/
- select:(const NXRect *)aRect inView:controlView editor:textObj delegate:anObject start:(int)selStart length:(int)selLength
{
/* do what the superclass would do */
[super select:aRect inView:controlView editor:textObj
delegate:anObject start:selStart length:selLength];
theCell = self;
if (maxLength && originalText)
strcpy(originalText, [self stringValue]);
[textObj setTextFilter:(NXTextFilterFunc)customTextFilter];
[textObj setCharFilter:autoJumpCharFilter];
return self;
}
/* The primary reason I've overridden edit: and select: (above) is to set
* the local static variable "theCell" to self. The filter functions must know
* about the current cell in order to query it for information on length,
* autojumping, etc. The only way that a cell becomes active are
* through one of these methods.
*/
- edit:(const NXRect *)aRect inView:controlView editor:textObj delegate:anObject event:(NXEvent *)theEvent
{
/* do what the superclass would do */
[super edit:aRect inView:controlView editor:textObj
delegate:anObject event:theEvent];
theCell = self;
if (maxLength && originalText)
strcpy(originalText, [self stringValue]);
[textObj setTextFilter:(NXTextFilterFunc)customTextFilter];
[textObj setCharFilter:autoJumpCharFilter];
return self;
}
- setMaxLength: (int) length
{
if (originalText)
{
free(originalText);
originalText = NULL;
}
maxLength = length;
if (length)
originalText = (char *)malloc(maxLength);
return self;
}
- (int) maxLength;
{
return maxLength;
}
- setAutoJump: (BOOL) flag forLength: (int)length
{
autoJump = flag;
[self setMaxLength: length];
return self;
}
- (BOOL) autoJump
{
return autoJump;
}
- setAcceptsReturn: (BOOL) flag
{
acceptsReturn = flag;
return self;
}
- (BOOL) acceptsReturn
{
return acceptsReturn;
}
- setOriginalText: (char *)aString
{
if (originalText)
strcpy(originalText, aString);
return self;
}
- (char *)originalText
{
return originalText;
}
- setCustomFilter: (NXTextFilterFunc) aFilter;
{
customTextFilter = (NXTextFilterFunc)aFilter;
return self;
}
- (NXTextFilterFunc) customTextFilter
{
return (NXTextFilterFunc) customTextFilter;
}
/* Run the given string through the Cell's text filter to
* see if it passes muster.
*/
- (BOOL) checkString: (char *)aString
{
int i, len;
char *cp;
id textObj;
void *fooPtr;
if (customTextFilter == (NXTextFilterFunc)nil)
return YES;
textObj = [[[self controlView] window] getFieldEditor :YES for: self];
for (i = 0, cp = aString; i < strlen(aString); i++, cp++)
{
len = 1;
// fooPtr will eliminate a compiler warning about "unused value"
fooPtr = (void*)(*(NXTextFilterFunc)customTextFilter)((id)textObj,
(unsigned char *)cp, (int *)&len, (int)i);
if (len == 0)
return NO;
}
return YES;
}
// This is the default text filter. If another has been installed via the setCustomFilter:
// method, then this one will not get called.
char *lengthFilter(id textObj, char *inputText, int *inputLength, int position)
{
int maxLength;
BOOL autoJump;
maxLength = [theCell maxLength];
autoJump = [theCell autoJump];
if (maxLength && !autoJump && [textObj textLength] > maxLength)
{
*inputLength = 0;
return "";
}
return inputText;
}
// This could easily be extended to include letters with diacritics.
// See Chapter 6 Summary for KeyInfo for a full listing of keyboard
// event information.
#define IS_VALID_ASCII(ch) ((ch) >= ' ' && (ch) <= '~')
unsigned short autoJumpCharFilter(unsigned short charCode, int flags, unsigned
short charSet)
{
NXSelPt start, end;
NXEvent *event, fakeEvent;
id textObj;
int curLength, maxLength;
BOOL autoJump, acceptsReturn;
maxLength = [theCell maxLength];
autoJump = [theCell autoJump];
acceptsReturn = [theCell acceptsReturn];
event = [NXApp currentEvent];
textObj = [[[theCell controlView] window] getFieldEditor :YES for: theCell];
curLength = [textObj textLength] +1;
/* Anything that's highlighted is going to get clobbered, so let's adjust */
[textObj getSel: &start : &end];
if (start.cp != end.cp)
curLength -= end.cp - start.cp;
// Currently acceptsReturn doesn't work very well with maxLength because
// it counts newlines which you probably don't want. If you want something
// more sophisticated then you'll have to parse the runs!
if (acceptsReturn && charCode == NX_CR)
return NXEditorFilter(charCode, flags, charSet);
// Watch out for interpreted rather than real keystrokes -- let them
// through even though we have reached our maximum length.
if (autoJump && maxLength && curLength > maxLength &&
IS_VALID_ASCII(charCode))
{
fakeEvent = *event;
fakeEvent.time++;
DPSPostEvent(&fakeEvent, YES);
return NX_TAB;
}
return NXFieldFilter(charCode, flags, charSet);
}
@end